/** boxing.d - boxing/unboxing

 Written in the D programming language 1.0

Authors:	Wei Li <oldrev@gmail.com>
Copyright:	Copyright (c) 2007 by Wei Li.
License:	BSD

References:
	This Any class is a port of boost::any library
	Boost Library License: http://www.boost.org/LICENSE_1_0.txt
*/

module dotmars.runtime.boxing;

import dotmars.base.stdtypes;


private interface IHolder
{
	TypeInfo type();
	IHolder  clone();
}

private final class Holder(ValueType) : IHolder
{
	this(ValueType value) {
		held = value;
	}

	public TypeInfo type() {
		return typeid(ValueType);
	}

	public IHolder clone() {
		return new Holder!(ValueType)(held);
	}

	ValueType held;
}


final class Any 
{
	IHolder m_content = null;

	//factory method
	public static Any opCall(T)(T t) 
	{
		Any a = new Any();
		a.assign(t);
		return a;
	}

	//factory method
	public static Any opCall()() {
		return new Any();
	}

	public this()
	{
		m_content = null;
	}

	public this(Any b)
	{
		m_content = b.m_content.clone();
	}

	public Any opAssign(ValueType)(ValueType value) 
	{
		m_content = new Holder!(ValueType)(value);
		return this;
	}

	public Any assign(ValueType)(ValueType value) 
	{
		static if (is(ValueType == Any)) 
			m_content = value.m_content !is null ? value.m_content.clone() : null;
		else 
			m_content = new Holder!(ValueType)(value);
		return this;
	}

	public bool empty() 
	{
		return (m_content is null);
	}

	public void clear() 
	{
		m_content = null;
	}

	public TypeInfo type() 
	{
		return m_content is null ? typeid(void) : m_content.type;
	}

	public ValueType as(ValueType)() {
		assert(!empty);
		assert(type == typeid(ValueType));

		auto p = cast(Holder!(ValueType))(m_content);
		return p.held;
	}

	public Any swap(Any rhs) {
		IHolder p = m_content;
		m_content = rhs.m_content;
		rhs.m_content=p;
		return this;
	}


}


//the C#-like Anying function 
Any box(T)(T v)
{
	//the referenced type is not allowed
	static assert((!is(T == class)) && (!is(T == interface)), "Error: Invalid Type");
	return Any(v);
}


//unAnying
T unbox(T)(Any b)
{
	return b.as!(T)();
}

